home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d8 / pdriver5.arc / SLIP8250.ASM < prev    next >
Assembly Source File  |  1989-12-17  |  24KB  |  948 lines

  1. version    equ    3
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
  6. ;8250 by Russell Nelson.  Any bugs are due to Russell Nelson.
  7.  
  8. ;  Copyright, 1988, 1989, Russell Nelson
  9.  
  10. ;   This program is free software; you can redistribute it and/or modify
  11. ;   it under the terms of the GNU General Public License as published by
  12. ;   the Free Software Foundation, version 1.
  13. ;
  14. ;   This program is distributed in the hope that it will be useful,
  15. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. ;   GNU General Public License for more details.
  18. ;
  19. ;   You should have received a copy of the GNU General Public License
  20. ;   along with this program; if not, write to the Free Software
  21. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23. code    segment    byte public
  24.     assume    cs:code, ds:code
  25.  
  26. ;8250 definitions
  27. ;Control/status register offsets from base address
  28. THR    equ    0        ;Transmitter holding register
  29. RBR    equ    0        ;Receiver buffer register
  30. DLL    equ    0        ;Divisor latch LSB
  31. DLM    equ    1        ;Divisor latch MSB
  32. IER    equ    1        ;Interrupt enable register
  33. IIR    equ    2        ;Interrupt ident register
  34. FCR    equ    2        ;16550 FIFO control register
  35. LCR    equ    3        ;Line control register
  36. MCR    equ    4        ;Modem control register
  37. LSR    equ    5        ;Line status register
  38. MSR    equ    6        ;Modem status register
  39.  
  40. ;8250 Line Control Register
  41. LCR_5BITS    equ    0    ;5 bit words
  42. LCR_6BITS    equ    1    ;6 bit words
  43. LCR_7BITS    equ    2    ;7 bit words
  44. LCR_8BITS    equ    3    ;8 bit words
  45. LCR_NSB        equ    4    ;Number of stop bits
  46. LCR_PEN        equ    8    ;Parity enable
  47. LCR_EPS        equ    10h    ;Even parity select
  48. LCR_SP        equ    20h    ;Stick parity
  49. LCR_SB        equ    40h    ;Set break
  50. LCR_DLAB    equ    80h    ;Divisor Latch Access Bit
  51.  
  52. ;16550 Line Control Register
  53. FCR_RCVR    equ    002h    ;Reset Receive FIFO
  54. FCR_XMIT    equ    004h    ;Reset Transmit FIFO
  55. FCR_1        equ    001h    ;One byte FIFO
  56. FCR_4        equ    041h    ;Four byte FIFO
  57. FCR_8        equ    081h    ;Eight byte FIFO
  58. FCR_14        equ    0c1h    ;Fourteen byte FIFO
  59.  
  60. ;8250 Line Status Register
  61. LSR_DR    equ    1    ;Data ready
  62. LSR_OE    equ    2    ;Overrun error
  63. LSR_PE    equ    4    ;Parity error
  64. LSR_FE    equ    8    ;Framing error
  65. LSR_BI    equ    10h    ;Break interrupt
  66. LSR_THRE equ    20h    ;Transmitter line holding register empty
  67. LSR_TSRE equ    40h    ;Transmitter shift register empty
  68.  
  69. ;8250 Interrupt Identification Register
  70. IIR_IP        equ    1    ;0 if interrupt pending
  71. IIR_ID        equ    6    ;Mask for interrupt ID
  72. IIR_RLS        equ    6    ;Receiver Line Status interrupt
  73. IIR_RDA        equ    4    ;Receiver data available interrupt
  74. IIR_THRE    equ    2    ;Transmitter holding register empty int
  75. IIR_MSTAT    equ    0    ;Modem status interrupt
  76.  
  77. ;8250 interrupt enable register bits
  78. IER_DAV    equ    1    ;Data available interrupt
  79. IER_TxE    equ    2    ;Tx buffer empty interrupt
  80. IER_RLS    equ    4    ;Receive line status interrupt
  81. IER_MS    equ    8    ;Modem status interrupt
  82.  
  83. ;8250 Modem control register
  84. MCR_DTR    equ    1    ;Data Terminal Ready
  85. MCR_RTS    equ    2    ;Request to Send
  86. MCR_OUT1 equ    4    ;Out 1 (not used)
  87. MCR_OUT2 equ    8    ;Master interrupt enable (actually OUT 2)
  88. MCR_LOOP equ    10h    ;Loopback test mode
  89.  
  90. ;8250 Modem Status Register
  91. MSR_DCTS equ    1    ;Delta Clear-to-Send
  92. MSR_DDSR equ    2    ;Delta Data Set Ready
  93. MSR_TERI equ    4    ;Trailing edge ring indicator
  94. MSR_DRLSD equ    8    ;Delta Rx Line Signal Detect
  95. MSR_CTS equ    10h    ;Clear to send
  96. MSR_DSR equ    20h    ;Data set ready
  97. MSR_RI    equ    40h    ;Ring indicator
  98. MSR_RLSD equ    80h    ;Received line signal detect
  99.  
  100. ;Slip Definitions
  101. FR_END        equ    0c0h        ;Frame End
  102. FR_ESC        equ    0dbh        ;Frame Escape
  103. T_FR_END    equ    0dch        ;Transposed frame end
  104. T_FR_ESC    equ    0ddh        ;Transposed frame escape
  105.  
  106.     public    int_no
  107. int_no        db    4,0,0,0        ; interrupt number.
  108. io_addr        dw    03f8h,0        ; I/O address for COM1.
  109. baud_rate    dw    12c0h,0        ; We support baud rates higher than 65535.
  110. baudclk        label    word
  111.         dd    115200        ;1.8432 Mhz / 16
  112.  
  113.     public    driver_class, driver_type, driver_name
  114. driver_class    db    6,0,0,0        ;from the packet spec
  115. driver_type    db    0,0,0,0        ;from the packet spec
  116. driver_name    db    'SLIP8250',0    ;name of the driver.
  117.  
  118.   ifdef debug
  119.     public recv_buf_size, recv_buf,    recv_buf_end, recv_buf_head
  120.     public recv_buf_tail, recv_pkt_ready
  121.   endif
  122. recv_buf_size    dw    3000        ;receive buffer size
  123. recv_buf    dw    ?        ;->receive buffer
  124. recv_buf_end    dw    ?        ;->after end of buffer
  125. recv_buf_head    dw    ?        ;->next character to get
  126. recv_buf_tail    dw    ?        ;->next character to store
  127. recv_pkt_ready    dw    0        ; flag indicating a packet is ready
  128.  
  129.   ifdef debug
  130.     public send_buf
  131.   endif
  132. send_buf_size    dw    3000        ;send buffer size
  133. send_buf    dw    ?        ;->send buffer
  134. send_buf_end    dw    ?        ;->after end of buffer
  135. send_buf_head    dw    ?        ;->next character to get
  136. send_buf_tail    dw    ?        ;->next character to store
  137.  
  138.   ifdef debug
  139.     public packet_sem, pkt_send_sem, xmit_time
  140.   endif
  141. packet_sem    dw    0        ; semaphore for    packets received
  142. pkt_send_sem    dw    0        ; semaphore for    packets xmitted
  143. asyrxint_cnt    dw    0        ; loop counter in asyrxint
  144. xmit_time    dw    0        ; loop timer for asyrxint
  145.  
  146.     public    rcv_modes
  147. rcv_modes    dw    4        ;number    of receive modes in our table.
  148.         dw    0,0,0,rcv_mode_3
  149.  
  150.  
  151.     public    send_pkt
  152. ;
  153. ; mod 7/25/89 John Grover
  154. ; - operates with interrupts on. Xmits one byte per interrupt
  155. ; - only turns transmitter buffer empty interrupt off when
  156. ; - all bytes of all packets are transmitted.
  157.  
  158. send_pkt:
  159. ;enter with ds:si -> packet, cx = packet length.
  160. ;exit with nc if ok, or else cy if error, dh set to error number.
  161. ;called from telnet layer via software interrupt
  162.     assume    ds:nothing
  163.  
  164.     push    cs
  165.     pop    es
  166.     mov    di,send_buf_tail
  167.     sti                ; enable interrupts
  168.  
  169.     mov    al,FR_END        ;Flush out any line garbage
  170.     call    send_char
  171.  
  172. ;Copy input to output, escaping special characters
  173. send_pkt_1:
  174.     lodsb
  175.     cmp    al,FR_ESC        ;escape FR_ESC with FR_ESC and T_FR_ESC
  176.     jne    send_pkt_2
  177.     mov    al,FR_ESC
  178.     call    send_char
  179.     mov    al,T_FR_ESC
  180.     jmp    short send_pkt_3
  181. send_pkt_2:
  182.     cmp    al,FR_END        ;escape FR_END with FR_ESC and T_FR_END
  183.     jne    send_pkt_3
  184.     mov    al,FR_ESC
  185.     call    send_char
  186.     mov    al,T_FR_END
  187. send_pkt_3:
  188.     call    send_char
  189.     loop    send_pkt_1
  190.     mov    al,FR_END        ;terminate it with a FR_END
  191.     call    send_char
  192.     mov    send_buf_tail,di
  193.  
  194.     inc    pkt_send_sem        ; increment the semaphore
  195.     cmp    pkt_send_sem, 1        ; see if we need to enable
  196.                     ; xmit buffer empty interrupt
  197.     ja    send_pkt_end
  198.  
  199. ;Enable modem status and (maybe) transmitter buffer empty interrupt.
  200.  
  201.     loadport
  202.     setport    MSR
  203.     mov    ah, IER_MS        ; always enable modem status interrupt
  204.     in    al, dx            ; check if clear to send
  205.     test    al, MSR_CTS
  206.     jz    send_pkt_4        ; no - won't enable xmit buffer empty interrupt
  207.  
  208.     or    ah,IER_TxE        ; yes - enable xmit buffer empty interrupt
  209.  
  210. send_pkt_4:
  211.     loadport
  212.     setport    IER
  213.     call    setbit            ; enable
  214.     cli
  215. send_pkt_end:
  216.     clc
  217.     ret
  218.  
  219. ;
  220. ; mod 7/25/89 John Grover
  221. ; - utilizes buffer pointers to ascertain if the
  222. ; - buffer has room for    another character
  223. ;
  224.  
  225. send_char:
  226. ;stuff the character in al into the transmit buffer, but only if there
  227. ;is enough room, otherwise ignore the char.
  228.     assume    ds:nothing
  229.  
  230.     cmp    di, send_buf_head    ;are we out of buffer?
  231.     jne    send_char_ok        ;no - continue
  232.     cmp    pkt_send_sem, 0        ;maybe - if no packets then no
  233.     jne    send_char_1        ;if there are packets then yes
  234.  
  235. send_char_ok:
  236.     stosb                ;store the char.
  237.     cmp    di,send_buf_end        ;do we need to wrap around?
  238.     jne    send_char_1        ;no.
  239.     mov    di,send_buf        ;yes - reload with beginning.
  240. send_char_1:
  241.     ret
  242.  
  243.  
  244.     public    get_address
  245. get_address:
  246. ;get the address of the interface.
  247. ;enter with es:di -> place to get the address, cx = size of address buffer.
  248. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  249.     assume    ds:code
  250.     mov    cx,0
  251.     clc
  252.     ret
  253.  
  254.  
  255.     public    set_address
  256. set_address:
  257. ;set the address of the interface.
  258. ;enter with es:di -> place to get the address, cx = size of address buffer.
  259. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  260.     assume    ds:nothing
  261.     clc
  262.     ret
  263.  
  264.  
  265. rcv_mode_3:
  266. ;receive mode 3 is the only one we support, so we don't have to do anything.
  267.     ret
  268.  
  269.  
  270.     public    set_multicast_list
  271. set_multicast_list:
  272. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  273. ;return nc if we set all of them, or cy,dh=error if we didn't.
  274.     mov    dh,NO_MULTICAST
  275.     stc
  276.     ret
  277.  
  278.  
  279.     public    get_multicast_list
  280. get_multicast_list:
  281. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  282. ;return    cy, NO_ERROR if we don't remember all of the addresses ourselves.
  283. ;return cy, NO_MULTICAST if we don't implement multicast.
  284.     mov    dh,NO_MULTICAST
  285.     stc
  286.     ret
  287.  
  288.  
  289.     public    reset_interface
  290. reset_interface:
  291. ;reset the interface.
  292.     assume    ds:code
  293.     ret
  294.  
  295.  
  296. ;called    when we    want to determine what to do with a received packet.
  297. ;enter with cx = packet length, es:di -> packet type.
  298.     extrn    recv_find: near
  299.  
  300. ;called after we have copied the packet into the buffer.
  301. ;enter with ds:si ->the packet, cx = length of the packet.
  302.     extrn    recv_copy: near
  303.  
  304.     extrn    count_in_err: near
  305.     extrn    count_out_err: near
  306.  
  307.     public    recv
  308.  
  309. ;
  310. ; mod 7/25/89 John Grover
  311. ;
  312. ; - added code to check modem status change interrupt. If CTS is
  313. ; - low  turn off transmitter buffer empty interrupt. If CTS is
  314. ; - high turn it on.
  315.  
  316. recv:
  317. ;called from the recv isr.  All registers have been saved, and ds=cs.
  318. ;Upon exit, the interrupt will be acknowledged.
  319.     assume    ds:code
  320. recv_2:
  321.     loadport
  322.     setport    IIR
  323.     in    al,dx            ;any interrupts at all?
  324.     test    al,IIR_IP
  325.     jne    recv_1            ;no.
  326.     and    al,IIR_ID
  327.     cmp    al,IIR_RDA        ;Receiver interrupt
  328.     jne    recv_3
  329.     call    asyrxint
  330.     jmp    recv_2
  331. recv_3:
  332.     cmp    al,IIR_THRE        ;Transmit interrupt
  333.     jne    recv_5
  334.     call    asytxint
  335.     jmp    recv_2
  336. recv_5:
  337. ;process IIR_MSTAT here.
  338. ;  If CTS and packet ready then
  339. ;    enable the    transmit buffer empty interrupt
  340. ;  else
  341. ;    disable the transmit buffer empty interrupt
  342. ;
  343.     cmp    al, IIR_MSTAT
  344.     jne    recv_4
  345.     setport    MSR            ; make sure of CTS status
  346.     mov    ah, IER_TxE        ; get ready to alter xmit buffer empty interrupt
  347.     in    al, dx
  348.     test    al, MSR_CTS        ; is CTS bit set
  349.     jz    recv_5_1        ; no - disable xmit buffer empty int
  350.     cmp    pkt_send_sem, 0        ; yes - is there a packet to xmit
  351.     jbe    recv_2            ; no - all done here
  352.     setport    IER            ; yes - enable xmit buffer empty int
  353.     call    setbit
  354.     jmp    recv_2
  355.  
  356. recv_5_1:
  357.     setport    IER
  358.     call    clrbit
  359.     jmp    recv_2
  360.  
  361. recv_4:
  362. ;process IIR_RLS here
  363. recv_1:
  364.     ret
  365.  
  366.  
  367. ;Process 8250 receiver interrupts
  368. ;
  369. ; mod 7/25/89 John Grover
  370. ; - this branches off when bps < 9600. See asyrxint_a.
  371. ; - Above 9600 bps we go into a loop to process a packet at
  372. ; - a time. If not data ready for a certain amount of time,
  373. ; - the process exits and waits for the next byte. This certain
  374. ; - amount of time to wait depends on the bps and CPU processor speed
  375. ; - and is determined in the initialization of the driver.
  376. ; - Upon receiving the FR_END character for the first frame in the
  377. ; - buffer a semaphore is set which tells recv_frame to run.
  378.  
  379. asyrxint:
  380.  
  381.     push    ds            ; get set up for the routine
  382.     pop    es
  383.         xor     bx, bx
  384.         cmp     baud_rate, 9600         ; below 9600 we're strictly
  385.         jbe     asyrxint_a              ; interrupt driven
  386.         mov     bx, xmit_time
  387. asyrxint_a:
  388.     mov    di,recv_buf_tail
  389.     xor    bp, bp            ; set flag to indicate 1st char
  390.                     ; processed
  391.         mov     si, packet_sem          ; optimization
  392.         loadport
  393.         mov     ah, LSR_DR
  394.  
  395. asyrxint_again:
  396.     xor    cx, cx            ; initialize counter
  397.     setport    LSR
  398. asyrxint_in:
  399.     in    al,dx            ; check for data ready
  400.     test    al,LSR_DR
  401.     jnz    asyrxint_gotit        ; yes - break out of loop
  402.     inc    cx            ; no - increase loop counter
  403.     cmp    cx, bx            ; timeout?
  404.     jae    asyrxint_exit        ; yes - leave
  405.     jmp    asyrxint_in        ; no - keep looping
  406.  
  407. asyrxint_gotit:
  408.     setport    RBR
  409.     in    al,dx
  410.  
  411. ;Process incoming data;
  412. ; If buffer is full, we have no choice but
  413. ; to drop the character
  414.  
  415.     cmp    di,recv_buf_head    ; check for buffer collision
  416.     jne    asyrxint_ok        ; none - continue
  417.         or      si, si                  ; maybe - if there are packets
  418.     jnz    asyrxint_exit        ; yes exit
  419.  
  420. asyrxint_ok:
  421.     stosb
  422.  
  423.     cmp    di,recv_buf_end        ; did we hit the end of the buffer?
  424.     jne    asyrxint_3        ; no.
  425.     mov    di,recv_buf        ; yes - wrap around.
  426.  
  427. asyrxint_3:
  428.     cmp    al,FR_END        ; might    this be    the end of a frame?
  429.     jne    asyrxint_reset        ; no - reset flag and loop
  430.         inc     si                      ; yes - indicate packet ready
  431.         cmp     si, 1                   ; determine if semaphore is <> 1
  432.         jne     asyrxint_chk_flg        ; yes - recv_frame must be active
  433.         inc     recv_pkt_ready          ; no - set flag to start recv_frame
  434.  
  435. asyrxint_chk_flg:
  436.         cmp     bp, 0                   ; was this the first char?
  437.         jne     asyrxint_1              ; no - exit handler
  438. asyrxint_reset:
  439.     inc    bp            ; set 1st character flag
  440.     jmp    asyrxint_again        ; get another character
  441.  
  442. asyrxint_exit:
  443. asyrxint_1:
  444.     mov    recv_buf_tail,di
  445.         mov     packet_sem, si
  446.  
  447.     ret
  448.  
  449.  
  450. ; --------------------------------------------------------------
  451. ;
  452. ;  recv_exiting
  453. ;
  454.     public    recv_exiting
  455. recv_exiting:
  456.         cmp     recv_pkt_ready, 1       ; is a packet ready?
  457.         jne     recv_isr_exit           ; no - skip to end
  458.     push    ax
  459.     push    bx
  460.     push    cx
  461.     push    dx
  462.     push    ds
  463.     push    es
  464.     push    bp
  465.     push    di
  466.     push    si
  467.     push    cs            ; point ds properly
  468.     pop    ds
  469.     mov    recv_pkt_ready,    0    ; reset flag
  470.         sti                             ; enable interrupts
  471.  
  472.     call    recv_frame
  473.  
  474.         cli
  475.     pop    si
  476.     pop    di
  477.     pop    bp
  478.     pop    es
  479.     pop    ds
  480.     pop    dx
  481.     pop    cx
  482.     pop    bx
  483.     pop    ax
  484. recv_isr_exit:
  485.     ret
  486.  
  487.  
  488. ; --------------------------------------------------------------
  489. ;
  490. ;  recv_frame
  491. ;
  492. ; mod 7/25/89 John Grover
  493. ;
  494. ; - recv_frame now operates with interrupts on. It is triggered
  495. ; - by the recv_pkt_ready flag and continues until all bytes
  496. ; - in all packets in the buffer have been transmitted to the upper
  497. ; - layer.
  498. ;
  499.   ifdef debug
  500.     public recv_frame
  501.   endif
  502. recv_frame:
  503.     cmp    packet_sem, 0        ; should we do this?
  504.     jz    recv_frame_end        ; no - exit
  505.     mov    si,recv_buf_head    ;process characters.
  506.     xor    cx,cx            ;count up the size here.
  507. recv_frame_1:
  508.  
  509.     call    recv_char        ;get a char.
  510.     je    recv_frame_2        ;go if no more chars.
  511.     cmp    al,FR_ESC        ;an escape?
  512.     je    recv_frame_1        ;yes - don't count this char.
  513.     inc    cx            ;no - count this one.
  514.     jmp    recv_frame_1
  515. recv_frame_2:
  516.  
  517.     jcxz    recv_frame_3        ;count zero? yes - just free the frame.
  518. ;we don't need to set the type because none are defined for SLIP.
  519.     push    si            ;save si in case we reject it.
  520.     push    bx
  521.     mov    di,0            ;but we avoid any segment end bullshit.
  522.     call    recv_find        ;look up our type.
  523.     pop    bx
  524.     pop    si
  525.  
  526.     mov    ax,es            ;is this pointer null?
  527.     or    ax,di
  528.     je    recv_frame_3        ;yes - just free the frame.
  529.  
  530.     push    cx
  531.     push    es            ;remember where the buffer pointer is.
  532.     push    di
  533.  
  534.     mov    si,recv_buf_head    ;process characters.
  535. recv_frame_4:
  536.     call    recv_char
  537.     je    recv_frame_6        ;yes - we're all done.
  538.     cmp    al,FR_ESC        ;an escape?
  539.     jne    recv_frame_5        ;no - just store it.
  540.  
  541.     call    recv_char        ;get the next character.
  542.     je    recv_frame_6
  543.     cmp    al,T_FR_ESC
  544.     mov    al,FR_ESC        ;assume T_FR_ESC
  545.     je    recv_frame_5        ;yup, that's it    - store FR_ESC
  546.     mov    al,FR_END        ;nope, store FR_END
  547. recv_frame_5:
  548.     stosb                ;store the byte.
  549.     jmp    recv_frame_4
  550. recv_frame_6:
  551.     mov    recv_buf_head,si    ;we're skipped to the end.
  552.  
  553.     pop    si            ;now give the frame to the client.
  554.     pop    ds
  555.     pop    cx
  556.     assume    ds:nothing
  557.  
  558.     call    recv_copy
  559.     push    cs
  560.     pop    ds
  561.     assume    ds:code
  562.     jmp    recv_frame_end
  563.  
  564. recv_frame_3:
  565.     mov    recv_buf_head,si    ;remember the new starting point.
  566. recv_frame_end:
  567.     dec    packet_sem
  568.     cmp    packet_sem, 0        ; are there more packets ready?
  569.         ja      recv_frame              ; yes - execute again
  570.     ret
  571.  
  572.  
  573. ; --------------------------------------------------------------
  574. ;
  575. ;  recv_char
  576. ;
  577. ; mod 7/25/89 John Grover
  578. ; - Now    uses buffer pointers to determine if there are
  579. ; - characters left.
  580. ;
  581.  
  582. recv_char:
  583. ;enter with si -> receive buffer, bx = receive count.  Wrap around if needed.
  584. ;return with nz, al = next char.  Return zr if there are no more chars in
  585. ;  this frame.
  586. ;
  587.     lodsb
  588.     cmp    si,recv_buf_end
  589.     jb    recv_char_1
  590.     mov    si,recv_buf
  591. recv_char_1:
  592.     mov    bx, recv_buf_tail
  593.     cmp    si, bx
  594.     je    recv_char_2
  595.     cmp    al,FR_END
  596. recv_char_2:
  597.     ret
  598.  
  599.  
  600. ;Handle 8250 transmitter interrupts
  601.  
  602. ; --------------------------------------------------------------
  603. ;
  604. ;  asytxint
  605. ;
  606. ; mod 7/25/89
  607. ; - Transmits one character and then exits. Upon last character
  608. ; - to transmit modem status and transmitter buffer empty interrupt
  609. ; - are disabled.
  610. ;
  611.  
  612. asytxint:
  613.  
  614. asytxint_2:
  615.  
  616. ;    loadport            ;can we load another character?
  617. ;    setport    LSR
  618. ;    in    al,dx
  619. ;    test    al,LSR_THRE
  620. ;    je    asytxint_1        ;no.
  621.  
  622.     mov    si,send_buf_head    ; yes - load one
  623.     lodsb                ;
  624.     cmp    si,send_buf_end        ;have we hit the end yet?
  625.     jne    asytxint_3        ;no.
  626.     mov    si,send_buf        ;yes - wrap around
  627. asytxint_3:
  628.     loadport
  629.     setport    THR
  630.     out    dx,al
  631.     mov    send_buf_head, si    ; store our location
  632.  
  633.  
  634.     cmp    si, send_buf_tail    ; more to xmit?
  635.     jne    asytxint_1        ; yes just exit
  636.  
  637. ;No more characters to transmit -- disable transmit interrupts.
  638.  
  639.     setport    IER            ;Disable transmit and modem
  640.     mov    ah,IER_TxE or IER_MS    ; status interrupts
  641.     call    clrbit
  642.     mov    pkt_send_sem, 0        ; indicate we're finished
  643. asytxint_1:
  644.  
  645.  
  646.        ret
  647.  
  648.  
  649.  
  650.  
  651. ;Set bit(s) in I/O port
  652. setbit:
  653. ;enter with dx = port, ah = bit to set.
  654.     in    al,dx
  655.     or    al,ah
  656.     out    dx,al
  657.     ret
  658.  
  659.  
  660. ;Clear bit(s) in I/O port
  661. clrbit:
  662. ;enter with dx = port, ah = bit to set.
  663.     in    al,dx
  664.     not    al            ;perform an and-not using DeMorgan's.
  665.     or    al,ah
  666.     not    al
  667.     out    dx,al
  668.     ret
  669.  
  670.  
  671. ;any code after this will not be kept after initialization.
  672. end_resident    label    byte
  673.  
  674.     public    usage_msg
  675. usage_msg    db    "usage: SLIP8250 packet_int_no [driver_class] [int_no] [io_addr] [baud_rate]",CR,LF
  676.         db    "   [send_buf_size] [recv_buf_size]",CR,LF
  677.         db    "   The driver_class should be SLIP, KISS, AX.25, or a number.",CR,LF,'$'
  678.  
  679.     public    copyright_msg
  680. copyright_msg    db    "Packet driver for SLIP8250, version ",'0'+majver,".",'0'+version,CR,LF
  681.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  682.  
  683. approximate_msg    db    "Warning: This baud rate can only be approximated using the 8250",CR,LF
  684.         db    "because it is not an even divisor of 115200",CR,LF,'$'
  685.  
  686. class_name    db    "Interface class ",'$'
  687. kiss_name    db    "KISS",CR,LF,'$'
  688. ax25_name    db    "AX.25",CR,LF,'$'
  689. slip_name    db    "SLIP",CR,LF,'$'
  690. int_no_name    db    "Interrupt number ",'$'
  691. io_addr_name    db    "I/O port ",'$'
  692. baud_rate_name    db    "Baud rate ",'$'
  693. send_buf_name    db    "Send buffer size ",'$'
  694. recv_buf_name    db    "Receive buffer size ",'$'
  695. unusual_com1    db    "That's unusual!  Com1 (0x3f8) usually uses interrupt 4!",CR,LF,'$'
  696. unusual_com2    db    "That's unusual!  Com2 (0x2f8) usually uses interrupt 3!",CR,LF,'$'
  697.  
  698.     extrn    set_recv_isr: near
  699.  
  700. ;enter with si -> argument string, di -> word to store.
  701. ;if there is no number, don't change the number.
  702.     extrn    get_number: near
  703.  
  704. ;enter with si -> argument string.
  705. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  706.     extrn    skip_blanks: near
  707.  
  708.  
  709.     public    parse_args
  710. parse_args:
  711.     call    skip_blanks
  712.     mov    al,[si]            ;now classify the argument.
  713.     or    al,20h            ;convert to lower case (assuming letter).
  714.     cmp    al,'k'
  715.     jne    parse_args_2
  716.     mov    driver_class,10        ;KISS, from packet spec.
  717.     mov    dx,offset kiss_name
  718.     jmp    short parse_args_1
  719. parse_args_2:
  720.     cmp    al,'s'
  721.     jne    parse_args_3
  722.     mov    driver_class,6        ;SLIP, from packet spec.
  723.     mov    dx,offset slip_name
  724.     jmp    short parse_args_1
  725. parse_args_3:
  726.     cmp    al,'a'
  727.     jne    parse_args_4
  728.     mov    driver_class,9        ;AX.25, from packet spec.
  729.     mov    dx,offset ax25_name
  730.     jmp    short parse_args_1
  731. parse_args_4:
  732.     mov    di,offset driver_class
  733.     mov    bx,offset class_name
  734.     call    get_number
  735.     jmp    short parse_args_6
  736. parse_args_1:
  737.     push    dx
  738.     mov    dx,offset class_name
  739.     mov    ah,9
  740.     int    21h
  741.     pop    dx
  742.     mov    ah,9
  743.     int    21h
  744. parse_args_5:
  745.     mov    al,[si]            ;skip to the next blank or CR.
  746.     cmp    al,' '
  747.     je    parse_args_6
  748.     cmp    al,CR
  749.     je    parse_args_6
  750.     inc    si            ;skip the character.
  751.     jmp    parse_args_5
  752. parse_args_6:
  753.     mov    di,offset int_no
  754.     mov    bx,offset int_no_name
  755.     call    get_number
  756.     mov    di,offset io_addr
  757.     mov    bx,offset io_addr_name
  758.     call    get_number
  759.     cmp    io_addr,03f8h        ;is this com1?
  760.     jne    ia_com2
  761.     mov    dx,offset unusual_com1
  762.     cmp    int_no,4        ;com1 usually uses int 1.
  763.     jne    ia_unusual
  764.     jmp    short ia_usual
  765. ia_com2:
  766.     cmp    io_addr,02f8h        ;is this com2?
  767.     jne    ia_usual        ;no.
  768.     mov    dx,offset unusual_com2
  769.     cmp    int_no,3        ;com2 usually uses int 3.
  770.     je    ia_usual
  771. ia_unusual:
  772.     mov    ah,9
  773.     int    21h
  774. ia_usual:
  775.     mov    di,offset baud_rate
  776.     mov    bx,offset baud_rate_name
  777.     call    get_number
  778.     mov    di,offset send_buf_size
  779.     mov    bx,offset send_buf_name
  780.     call    get_number
  781.     mov    di,offset recv_buf_size
  782.     mov    bx,offset recv_buf_name
  783.     call    get_number
  784.     ret
  785.  
  786.  
  787. ; --------------------------------------------------------------
  788. ;
  789. ;  etopen
  790. ;
  791. ; mod 7/25/89 John Grover
  792. ; - Contains a loop to determine a pseudo timeout for asyrxint.
  793. ; - The value is determined by transmitting characters in a
  794. ; - loop whose clock cycles are nearly the same as the "sister"
  795. ; - loop in asyrxint. The per character, maximum time used
  796. ; - basis which is then multiplied by a factor to achieve a timeout
  797. ; - value for the particular bps and CPU speed of the host.
  798.  
  799.     public    etopen
  800. etopen:
  801.     pushf
  802.     cli
  803.  
  804.     loadport            ;Purge the receive data buffer
  805.     setport    RBR
  806.     in    al,dx
  807.  
  808.     ;Enable FIFO, set FIFO trigger level to 8
  809.     mov    al,FCR_8
  810.     setport    FCR
  811.     out    dx,al
  812.  
  813.     ;Set line control register: 8 bits, no parity
  814.     mov    al,LCR_8BITS
  815.     setport    LCR
  816.     out    dx,al
  817.  
  818.     ;Turn on receive interrupt enable in 8250, leave transmit
  819.     ; and modem status interrupts turned off for now
  820.     mov    al,IER_DAV
  821.     setport    IER
  822.     out    dx,al
  823.  
  824.     ;Set modem control register: assert DTR, RTS, turn on 8250
  825.     ; master interrupt enable (connected to OUT2)
  826.  
  827.     mov    al,MCR_DTR or MCR_RTS or MCR_OUT2
  828.     setport    MCR
  829.     out    dx,al
  830.  
  831. ;compute the divisor given the baud rate.
  832.     mov    dx,baudclk+2
  833.     mov    ax,baudclk
  834.     mov    bx,0
  835. asy_speed_1:
  836.     inc    bx
  837.     sub    ax,baud_rate
  838.     sbb    dx,baud_rate+2
  839.     jnc    asy_speed_1
  840.     dec    bx
  841.     add    ax,baud_rate
  842.     adc    dx,baud_rate+2
  843.     or    ax,dx
  844.     je    asy_speed_2
  845.  
  846.     mov    dx,offset approximate_msg
  847.     mov    ah,9
  848.     int    21h
  849.  
  850. asy_speed_2:
  851.  
  852.     loadport            ;Purge the receive data buffer
  853.     setport    RBR
  854.     in    al,dx
  855.  
  856.     mov    ah,LCR_DLAB        ;Turn on divisor latch access bit
  857.     setport    LCR
  858.     call    setbit
  859.  
  860.     mov    al,bl            ;Load the two bytes of the divisor.
  861.     setport    DLL
  862.     out    dx,al
  863.     mov    al,bh
  864.     setport    DLM
  865.     out    dx,al
  866.  
  867.     mov    ah,LCR_DLAB        ;Turn off divisor latch access bit
  868.     setport    LCR
  869.     call    clrbit
  870.  
  871.     call    set_recv_isr        ;Set interrupt vector to SIO handler
  872.  
  873. ;set up the various pointers.
  874.     mov    dx,offset end_resident
  875.     mov    send_buf,dx
  876.     mov    send_buf_head,dx
  877.     mov    send_buf_tail,dx
  878.     add    dx,send_buf_size
  879.     mov    send_buf_end,dx
  880.  
  881.     mov    recv_buf,dx
  882.     mov    recv_buf_head,dx
  883.     mov    recv_buf_tail,dx
  884.     add    dx,recv_buf_size
  885.     mov    recv_buf_end,dx
  886.  
  887.  
  888.     ; the following code attempts to determine a pseudo timeout
  889.     ; value    to use in the loop that waits for an incoming character
  890.     ; in asyrxint. The value returned in xmit_time is the number of
  891.     ; loops processed between characters - therefore the loop used below
  892.     ; is and should    remain similar to the loop used in asyrxint.
  893.  
  894.     push    dx
  895.     xor    ax, ax            ; we'll send a 0
  896.     mov    ah, LSR_THRE
  897.     mov    cx, 10h            ; take the highest of 16 runs
  898.     xor    si, si            ; will hold highest value
  899.  
  900. xmit_time_start:
  901.  
  902.     xor    di, di            ; initialize counter
  903.     loadport
  904.     setport    THR            ; xmit a character
  905.     out    dx, al
  906.     setport    LSR               ; set up    to check for an empty buffer
  907.  
  908.     ; next is the loop actually being timed
  909.  
  910. xmit_time_top:
  911.     in    al, dx
  912.     test    al, ah
  913.     jnz    xmit_time_done
  914.     inc    di
  915.     cmp    cx, cx            ; these next few instructions do nothing
  916.     jmp    xmit_time_1        ;  except maintain similarity with the
  917.                     ;  "sister" loop in asyrxint
  918. xmit_time_1:
  919.     jmp    xmit_time_top
  920.  
  921. xmit_time_done:                ; end of timed loop
  922.  
  923.  
  924.  
  925.     cmp    si, di            ; compare highest value with new value
  926.     ja    xmit_time_end        ; no bigger - just loop
  927.     mov    si, di            ; bigger - save it
  928.  
  929. xmit_time_end:
  930.     loop    xmit_time_start        ; bottom of outer loop
  931.  
  932.     shl    si, 1            ; we'll wait 8 characters worth
  933.     shl    si, 1
  934.     shl    si, 1
  935.     mov    xmit_time, si        ; retain largest value
  936.     pop    dx
  937.  
  938.     ; end of pseudo timer determination
  939.  
  940.  
  941.     popf
  942.     clc                ;indicate no errors.
  943.     ret
  944.  
  945. code    ends
  946.  
  947.     end
  948.